/*
 * @Copyright: 2017 www.yyfax.com Inc. All rights reserved.
 */
package com.yyfax.pay.third.service;

import java.net.SocketTimeoutException;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.NotImplementedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.yyfax.framework.common.Log;
import com.yyfax.pay.common.enums.PayModeEnum;
import com.yyfax.pay.common.enums.PayTypeEnum;
import com.yyfax.pay.common.exception.PayException;
import com.yyfax.pay.common.exception.PayExceptionCode;
import com.yyfax.pay.order.model.to.payin.PayinBatchOrderYYContent;
import com.yyfax.pay.order.model.to.payin.PayinBatchVo;
import com.yyfax.pay.order.model.to.payin.PayinOrderYYContent;
import com.yyfax.pay.order.model.to.payin.PayinSnapshotVo;
import com.yyfax.pay.order.model.to.payin.QueryBatchPayinOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.AuthenticationYYContent;
import com.yyfax.pay.third.model.to.yyfax.AuthenticationYYParams;
import com.yyfax.pay.third.model.to.yyfax.DataBinder;
import com.yyfax.pay.third.model.to.yyfax.MerchantConfigExtContent;
import com.yyfax.pay.third.model.to.yyfax.OrderNotifyContent;
import com.yyfax.pay.third.model.to.yyfax.OrderReturnContent;
import com.yyfax.pay.third.model.to.yyfax.PayOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.PayOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.PayReturnParams;
import com.yyfax.pay.third.model.to.yyfax.PayWebFormContent;
import com.yyfax.pay.third.model.to.yyfax.PayoutBatchOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.PayoutBatchOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.PayoutDataBinder;
import com.yyfax.pay.third.model.to.yyfax.PayoutOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.PayoutOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.PayoutRefundDataBinder;
import com.yyfax.pay.third.model.to.yyfax.QueryBatchPayoutOrderCheckYYContent;
import com.yyfax.pay.third.model.to.yyfax.QueryBatchPayoutOrderCheckYYParams;
import com.yyfax.pay.third.model.to.yyfax.QueryBatchPayoutOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.QueryBatchPayoutOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.QueryCardBinContent;
import com.yyfax.pay.third.model.to.yyfax.QueryCardBinParams;
import com.yyfax.pay.third.model.to.yyfax.QueryPayOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.QueryPayOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.QueryPayoutOrderYYContent;
import com.yyfax.pay.third.model.to.yyfax.QueryPayoutOrderYYParams;
import com.yyfax.pay.third.model.to.yyfax.SendAuthenticationVerifyCodeYYContent;
import com.yyfax.pay.third.model.to.yyfax.SendAuthenticationVerifyCodeYYParams;
import com.yyfax.pay.third.model.to.yyfax.SendVerifyCodeYYContent;
import com.yyfax.pay.third.model.to.yyfax.SendVerifyCodeYYParams;
import com.yyfax.pay.third.model.to.yyfax.WebFormYYContent;
import com.yyfax.pay.third.model.to.yyfax.WebFormYYParams;
import com.yyfax.pay.third.model.to.yyfax.WithoutVerifyYYContent;
import com.yyfax.pay.third.model.to.yyfax.WithoutVerifyYYParams;
import com.yyfax.pay.third.model.to.yyfax.payin.QueryPayinOrderYYContent;

/**
 * <h1>支付通道接口封装</h1>
 * <p>
 * 统一对内接口及参数;<br>
 * </p>
 * 
 * @author jiangmy
 * @date 2017-04-11 09:56:07
 * @since v1.0.0
 */
public abstract class ThirdPayService {

	/**
	 * @Fields facadeName 各个通道的外观模式名称
	 */
	protected String facadeName = "";

	private static final Logger logger = LoggerFactory.getLogger(ThirdPayService.class);

	/**
	 * 1.查单；
	 * 
	 * @author jiangmy
	 * @date 2017-04-11 10:06:18
	 * @since v1.0.0
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public QueryPayOrderYYContent queryOrder(QueryPayOrderYYParams req) throws Exception {
		throw new NotImplementedException(facadeName + "查单不支持");
	}

	/**
	 * 2.独立鉴权获取验证码；
	 * 
	 * @author jiangmy
	 * @date 2017-04-11 10:41:32
	 * @since v1.0.0
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public SendAuthenticationVerifyCodeYYContent sendAuthenticationVerifyCode(SendAuthenticationVerifyCodeYYParams req) throws Exception {
		throw new NotImplementedException(facadeName + "独立鉴权获取验证码不支持");
	}

	/**
	 * 3.独立鉴权请求；
	 * 
	 * @author jiangmy
	 * @date 2017-04-11 10:41:50
	 * @since v1.0.0
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public AuthenticationYYContent authentication(AuthenticationYYParams req) throws Exception {
		throw new NotImplementedException(facadeName + "独立鉴权不支持");
	}

	/**
	 * 调用无验证码鉴权接口
	 * 
	 * @author xulqb
	 * @date 2017/12/21 14:19
	 * @param [req]
	 * @return
	 * @since V1.0.0
	 */
	public WithoutVerifyYYContent authenticationWithout(WithoutVerifyYYParams req) throws Exception {
		throw new NotImplementedException(facadeName + "独立鉴权不支持");
	}

	/**
	 * 4.支付获取验证码；<br>
	 * 插入支付日志
	 * 
	 * @author jiangmy
	 * @date 2017-04-11 10:43:34
	 * @since v1.0.0
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public SendVerifyCodeYYContent sendVerifyCode(SendVerifyCodeYYParams req) throws Exception {
		throw new NotImplementedException(facadeName + "支付获取验证码不支持");
	}

	/**
	 * 5.支付请求；<br>
	 * 插入支付日志
	 * 
	 * @author jiangmy
	 * @date 2017-04-11 10:43:43
	 * @since v1.0.0
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public PayOrderYYContent payOrder(PayOrderYYParams req) throws Exception {
		throw new NotImplementedException(facadeName + "支付请求不支持");
	}

	/**
	 * 6.代付请求；
	 * 
	 * @deprecated 作废，使用新接口{@linkplain com.yyfax.pay.third.service.ThirdPayService#compositePayoutOder},edit by buyi since 2.1.5
	 * @author jiangmy
	 * @date 2017-04-11 10:44:04
	 * @since v1.0.0
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public PayoutOrderYYContent payoutOrder(PayoutOrderYYParams req) throws Exception {
		// throw new NotImplementedException(facadeName + "代付不支持");
		logger.warn(Log.op("ThirdPayService.payoutOrder").msg("代付失败 | 该商户不支持该支付通道").kv("merchantCode", req.getMerchantCode())
				.kv("payoutOrderId", req.getPayoutOrderId()).toString());
		throw PayExceptionCode.ERROR_NOT_SUPPORT_PAYMENT.exp();
	}

	/**
	 * 代付入口
	 * 
	 * @author buyi
	 * @date 2018-05-12 00:59:28
	 * @since v2.1.5
	 * @param req
	 * @return
	 */
	public PayoutDataBinder payoutOderComposite(PayoutOrderYYParams req) {
		final String op = "ThirdPayService.compositePayoutOder";
		PayoutDataBinder binder = createPayoutDataBinder(req);
		try {
			// 发起代付请求
			payoutOrderNew(req, binder);
		} catch (SocketTimeoutException e) {
			// 请求超时
			logger.error(Log.op(op).msg("代付出现超时").kv("merchantCode", req.getMerchantCode()).kv("payoutOrderId", req.getPayoutOrderId()).toString(),
					e);

			binder.setException(e);
			binder.setResult(PayExceptionCode.WARN_REQ_TIME_OUT);
		} catch (PayException e) {
			logger.error(Log.op(op).msg("代付出现业务异常").kv("merchantCode", req.getMerchantCode()).kv("payoutOrderId", req.getPayoutOrderId()).toString(),
					e);
			binder.setException(e);
			binder.setResult(e.getCode(), e.getMessage());
		} catch (Exception e) {
			logger.error(Log.op(op).msg("代付出现未知异常，修改状态为未知").kv("merchantCode", req.getMerchantCode()).kv("payoutOrderId", req.getPayoutOrderId())
					.toString(), e);
			binder.setException(e);
			binder.setResult(PayExceptionCode.WARN_UNKNOWN);
		}

		return binder;
	}

	/**
	 * 代付请求
	 * 
	 * @author buyi
	 * @date 2018-05-12 01:48:59
	 * @since v2.1.5
	 * @param req
	 * @param binder
	 * @return
	 */
	protected void payoutOrderNew(PayoutOrderYYParams req, PayoutDataBinder binder) throws Exception {
		logger.warn(Log.op("ThirdPayService.payoutOrder").msg("代付失败 | 该商户不支持该支付通道").kv("merchantCode", req.getMerchantCode())
				.kv("payoutOrderId", req.getPayoutOrderId()).toString());
		throw PayExceptionCode.ERROR_NOT_SUPPORT_PAYMENT.exp();
	}

	/**
	 * 创建代付数据绑定
	 * 
	 * @author buyi
	 * @date 2018-05-12 01:53:20
	 * @since v2.1.5
	 * @param req
	 * @return
	 */
	private PayoutDataBinder createPayoutDataBinder(PayoutOrderYYParams req) {
		PayoutDataBinder binder = PayoutDataBinder.newInstance();
		binder.setPayoutOrderId(req.getPayoutOrderId());
		return binder;
	}

	/**
	 * 单笔代付查询
	 * 
	 * @author buyi
	 * @date 2017-04-18 18:35:35
	 * @since v1.0.0
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public QueryPayoutOrderYYContent queryPayoutOrder(QueryPayoutOrderYYParams req) throws Exception {
		throw new NotImplementedException(facadeName + "单笔代付查询不支持");
	}

	/**
	 * 7.批量代付请求；
	 * 
	 * @author jiangmy
	 * @date 2017-04-11 10:44:12
	 * @since v1.0.0
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public PayoutBatchOrderYYContent payoutBatchOrder(PayoutBatchOrderYYParams req) throws Exception {
		throw new NotImplementedException(facadeName + "批量代付不支持");
	}

	/**
	 * 8.批量代付查询；
	 * 
	 * @author jiangmy
	 * @date 2017-04-11 10:44:19
	 * @since v1.0.0
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public QueryBatchPayoutOrderYYContent queryBatchPayoutOrder(QueryBatchPayoutOrderYYParams req) throws Exception {
		throw new NotImplementedException(facadeName + "批量代付查询不支持");
	}

	/**
	 * 9.批量代付对账查询；
	 * 
	 * @author jiangmy
	 * @date 2017-04-11 10:44:27
	 * @since v1.0.0
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public QueryBatchPayoutOrderCheckYYContent batchPayoutOrderCheck(QueryBatchPayoutOrderCheckYYParams req) throws Exception {
		throw new NotImplementedException(facadeName + "批量代付对账不支持");
	}

	/**
	 * 查询卡bin
	 * 
	 * @author buyi
	 * @date 2017-04-12 17:23:01
	 * @since v1.0.0
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public QueryCardBinContent queryCardBin(QueryCardBinParams req) throws Exception {
		throw new NotImplementedException(facadeName + "查询卡bin不支持");
	}

	/**
	 * 封装form表单，用于页面提交<br>
	 * 
	 * <pre>
	 * 响应参数如果跳转到第三分收银台，则相应参数form根据第三方规则封装；
	 * 如果是支付模块的收银台，则参数指定为{@link PayWebFormContent}
	 * </pre>
	 * 
	 * @author buyi
	 * @date 2017-04-12 19:11:59
	 * @since v1.0.0
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public WebFormYYContent<?> transformWebForm(WebFormYYParams req) throws Exception {
		throw new NotImplementedException(facadeName + "不支持");
	}

	/**
	 * 解析支付同步请求<br>
	 * 支付模块同步响应请求为json格式的数据流，参数见{@link PayReturnParams}
	 * 
	 * @author buyi
	 * @date 2017-04-12 21:25:19
	 * @since v1.0.0
	 * @param request
	 * @return
	 * @throws Exception
	 */
	public OrderReturnContent transformPayOrderReturn(HttpServletRequest request) throws Exception {
		throw new NotImplementedException(facadeName + "不支持");
	}

	/**
	 * 解析支付异步请求
	 * 
	 * @author buyi
	 * @date 2017-04-12 21:25:38
	 * @since v1.0.0
	 * @param request
	 * @return
	 * @throws Exception
	 */
	public OrderNotifyContent transformPayOrderNotify(HttpServletRequest request) throws Exception {
		throw new NotImplementedException(facadeName + "不支持");
	}

	/**
	 * 解析代付异步请求
	 * 
	 * @author buyi
	 * @date 2017-04-18 11:49:18
	 * @since v1.0.0
	 * @param request
	 * @return
	 * @throws Exception
	 */
	public OrderNotifyContent transformPayoutOrderNotify(HttpServletRequest request) throws Exception {
		throw new NotImplementedException(facadeName + "不支持");
	}

	/**
	 * 批量代扣
	 * 
	 * @author maojian
	 * @date Apr 27, 2017 8:54:44 AM
	 * @since TODO(说明当前修改的版本号)
	 * @param PayinBatchVo
	 * @return
	 * @throws Exception
	 */
	public PayinBatchOrderYYContent payinBatchOrder(PayinBatchVo req) throws Exception {
		throw new NotImplementedException(facadeName + "批量代扣不支持");
	}

	/**
	 * 查询支付扩展信息
	 * 
	 * @author buyi
	 * @date 2017-04-27 17:24:31
	 * @since v1.0.0
	 * @param merchantCode
	 * @param payment
	 * @param paytType
	 * @param payMode
	 * @return
	 * @throws Exception
	 */
	public MerchantConfigExtContent queryMerchantConfigExt(String merchantCode, PayTypeEnum paytType, PayModeEnum payMode) throws Exception {
		throw new NotImplementedException(facadeName + "查询支付扩展信息不支持");
	}

	public QueryBatchPayinOrderYYContent queryBatchPayinOrder(PayinBatchVo req) throws Exception {
		throw new NotImplementedException(facadeName + "批量代扣查询不支持");
	}

	public PayinOrderYYContent payinOrder(PayinSnapshotVo payinSnapshot) throws Exception {
		throw new NotImplementedException(facadeName + "代扣不支持");
	}

	public QueryPayinOrderYYContent queryPayinOrder(PayinSnapshotVo payinOrderVO) throws Exception {
		throw new NotImplementedException(facadeName + "代扣查询不支持");
	}

	/**
	 * 解析代付退票请求
	 * 
	 * @author buyi
	 * @date 2018-05-23 15:06:20
	 * @since v2.1.5
	 * @param request
	 * @return
	 */
	public PayoutRefundDataBinder parsePayoutRefundNotifyComposite(String merchantCode, HttpServletRequest request) {
		final String op = "ThirdPayService.parsePayoutRefundNotifyComposite";
		PayoutRefundDataBinder binder = new PayoutRefundDataBinder();
		try {
			binder.setMerchantCode(merchantCode);

			getRefundNotifyResult(request, binder);

		} catch (Exception e) {
			logger.error(Log.op(op).msg("代付退票通知解析异常").kv("busiId", binder.getBusiId()).toString(), e);
			binder.setException(e);
		}

		return binder;
	}

	public void getRefundNotifyResult(HttpServletRequest request, PayoutRefundDataBinder binder) throws Exception {
		throw PayExceptionCode.ERROR_NOT_SUPPORT_PAYMENT.exp();
	}
}
